package com.example.shutdown_v1.service;

import com.example.shutdown_v1.constants.PowerDeviceConstants;
import com.example.shutdown_v1.repository.ShopRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.messaging.MessageChannel;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 电力设备管理服务
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class PowerDeviceService {
    
    private final RedisTemplate<String, Object> redisTemplate;
    private final ShopRepository shopRepository;
    
    @Autowired
    private MessageChannel mqttOutboundChannel;  // MQTT发布通道
    
    /**
     * 查询单路电路状态
     * @param merchantId 商家ID (当前版本暂不使用，为将来扩展预留)
     * @param channel 路数 (1-6)
     */
    public void querySingleChannel(String merchantId, int channel) {
        if (channel < 1 || channel > PowerDeviceConstants.MAX_CHANNELS) {
            throw new IllegalArgumentException("路数必须在1-6之间，当前值: " + channel);
        }

    // 占位注释：resolveCommandTopic 方法已移动到类作用域的后面
        
        String command = PowerDeviceConstants.QUERY_COMMANDS.get(channel);
        
        // 动态解析主题（按商家code配置），找不到则回退默认
        String currentTopic = resolveCommandTopic(merchantId);
        
        // 将来版本：发送到商家专用主题 (暂时注释)
        // String futureTopic = String.format(PowerDeviceConstants.Topics.FUTURE_COMMAND_TOPIC_FORMAT, merchantId);
        
        log.info("[电力查询] 商家:{}, 查询{}路, 指令:{}, 主题:{}", 
                merchantId, channel, command, currentTopic);
        
        // 发送MQTT指令
        sendMqttCommand(currentTopic, command);
        
        // 记录查询状态到Redis（用于追踪响应）
        try {
            String queryKey = PowerDeviceConstants.RedisKeys.POWER_QUERY_PREFIX + merchantId + ":" + channel;
            // 使用HashMap而不是Map.of()，避免序列化问题
            java.util.HashMap<String, Object> queryInfo = new java.util.HashMap<>();
            queryInfo.put("timestamp", System.currentTimeMillis());
            queryInfo.put("channel", channel);
            queryInfo.put("merchantId", merchantId);
            queryInfo.put("command", PowerDeviceConstants.QUERY_COMMANDS.get(channel));
            
            redisTemplate.opsForValue().set(queryKey, queryInfo, Duration.ofMinutes(5));
            log.debug("[电力查询] 已记录查询状态 - Key:{}", queryKey);
        } catch (Exception e) {
            log.warn("[电力查询] Redis记录查询状态失败 - 商家:{}, {}路", merchantId, channel, e);
        }
    }
    
    /**
     * 查询所有路电路状态（顺序执行，避免指令冲突）
     * @param merchantId 商家ID
     * @return 各路状态结果
     */
    @Async
    public CompletableFuture<Map<Integer, Boolean>> queryAllChannels(String merchantId) {
        log.info("[电力查询] 开始查询商家 {} 所有电路状态", merchantId);
        
        Map<Integer, Boolean> results = new ConcurrentHashMap<>();
        
        for (int channel = 1; channel <= PowerDeviceConstants.MAX_CHANNELS; channel++) {
            try {
                // 发送查询指令
                querySingleChannel(merchantId, channel);
                
                // 等待响应
                Boolean status = waitForChannelResponse(merchantId, channel, PowerDeviceConstants.QUERY_TIMEOUT_MS);
                results.put(channel, status != null ? status : false);
                
                log.info("[电力查询] 商家:{}, {}路状态:{}", 
                        merchantId, channel, status != null ? (status ? "有电" : "断电") : "超时");
                
                // 指令间隔，避免设备处理不过来
                if (channel < PowerDeviceConstants.MAX_CHANNELS) {
                    Thread.sleep(PowerDeviceConstants.COMMAND_INTERVAL_MS);
                }
                
            } catch (Exception e) {
                log.error("[电力查询] 商家:{}, {}路查询失败", merchantId, channel, e);
                results.put(channel, false); // 查询失败默认为断电
            }
        }
        
        // 更新商家整体断电状态
        updateMerchantPowerStatus(merchantId, results);
        
        log.info("[电力查询] 商家 {} 所有电路查询完成，结果: {}", merchantId, results);
        return CompletableFuture.completedFuture(results);
    }
    
    /**
     * 获取商家当前电力状态
     * @param merchantId 商家ID
     * @return 电力状态信息
     */
    public Map<String, Object> getMerchantPowerStatus(String merchantId) {
        try {
            String statusKey = PowerDeviceConstants.RedisKeys.MERCHANT_STATUS_PREFIX + merchantId;
            Map<Object, Object> status = redisTemplate.opsForHash().entries(statusKey);
            
            if (status.isEmpty()) {
                // 没有数据时，返回未知状态（简化为null）
                java.util.HashMap<String, Object> result = new java.util.HashMap<>();
                result.put("merchantId", merchantId);
                result.put("allPowerOff", null);
                result.put("channels", new java.util.HashMap<String, Boolean>());
                result.put("updateTime", null);
                result.put("hasData", false);
                result.put("message", "未查询到电力状态数据");
                return result;
            }
            
            java.util.HashMap<String, Object> result = new java.util.HashMap<>();
            result.put("merchantId", merchantId);
            result.put("allPowerOff", status.getOrDefault("allPowerOff", null));
            
            // 获取各路状态（简化为Boolean，去掉混淆的触发/未触发标签）
            @SuppressWarnings("unchecked")
            Map<String, Boolean> channels = (Map<String, Boolean>) status.getOrDefault("channels", java.util.Collections.emptyMap());
            
            result.put("channels", channels);
            result.put("updateTime", status.getOrDefault("updateTime", null));
            result.put("hasData", true);
            result.put("deviceStatus", "设备已接入并响应");
            return result;
        } catch (Exception e) {
            log.error("[电力状态] Redis连接失败 - 商家:{}", merchantId, e);
            java.util.HashMap<String, Object> result = new java.util.HashMap<>();
            result.put("merchantId", merchantId);
            result.put("deviceStatus", "系统异常");
            result.put("hasData", false);
            result.put("error", "Redis连接失败: " + e.getMessage());
            return result;
        }
    }
    
    /**
     * 处理设备响应数据
     * @param merchantId 商家ID
     * @param responseData 响应数据
     */
    public void handleDeviceResponse(String merchantId, String responseData) {
        log.info("[电力响应] 商家:{}, 响应数据:{}", merchantId, responseData);
        
        // 解析响应状态
        Boolean powerStatus = parsePowerStatus(responseData);
        if (powerStatus == null) {
            log.warn("[电力响应] 商家:{}, 无法解析状态数据:{}", merchantId, responseData);
            return;
        }
        
        // 确定是哪一路的响应
        Integer channel = determineResponseChannel(merchantId);
        if (channel != null) {
            String responseKey = PowerDeviceConstants.RedisKeys.POWER_RESPONSE_PREFIX + merchantId + ":" + channel;
            redisTemplate.opsForValue().set(responseKey, powerStatus, Duration.ofMinutes(1));
            
            // 同时更新整体状态（单路更新）
            updateSingleChannelStatus(merchantId, channel, powerStatus);
            
            log.info("[电力响应] 商家:{}, {}路状态解析完成 - {} (原始数据:{})", 
                    merchantId, channel, powerStatus ? "有电" : "断电", responseData);
        } else {
            log.warn("[电力响应] 商家:{}, 找不到对应的查询记录，可能是超时响应", merchantId);
        }
    }
    
    /**
     * 发送MQTT指令
     */
    private void sendMqttCommand(String topic, String command) {
        try {
            // 将十六进制字符串转换为字节数组
            byte[] hexBytes = hexStringToByteArray(command);
            
            boolean sent = mqttOutboundChannel.send(
                MessageBuilder.withPayload(hexBytes)
                    .setHeader("mqtt_topic", topic)
                    .build()
            );
            // 改为INFO级别，确保能看到发送日志
            log.info("[MQTT发送] 发送{} - 主题:{}, 指令:{}, 字节数:{}", 
                    sent ? "成功" : "失败", topic, command, hexBytes.length);
            
            if (!sent) {
                throw new RuntimeException("MQTT消息队列满或发送失败");
            }
        } catch (Exception e) {
            log.error("[MQTT发送] 发送失败 - 主题:{}, 指令:{}", topic, command, e);
            throw new RuntimeException("MQTT指令发送失败", e);
        }
    }
    
    /**
     * 将十六进制字符串转换为字节数组
     */
    private byte[] hexStringToByteArray(String hexString) {
        // 移除空格
        String cleanHex = hexString.replace(" ", "");
        
        // 确保长度为偶数
        if (cleanHex.length() % 2 != 0) {
            throw new IllegalArgumentException("十六进制字符串长度必须为偶数: " + hexString);
        }
        
        byte[] bytes = new byte[cleanHex.length() / 2];
        for (int i = 0; i < cleanHex.length(); i += 2) {
            bytes[i / 2] = (byte) Integer.parseInt(cleanHex.substring(i, i + 2), 16);
        }
        
        return bytes;
    }
    
    /**
     * 根据商家code解析指令发布主题，若未配置则回退默认主题
     */
    private String resolveCommandTopic(String merchantCode) {
        try {
            if (merchantCode == null || merchantCode.isEmpty()) {
                return PowerDeviceConstants.Topics.CURRENT_COMMAND_TOPIC;
            }
            return shopRepository.findByCode(merchantCode)
                    .map(shop -> {
                        String topic = shop.getPowerCommandTopic();
                        return (topic != null && !topic.isBlank())
                                ? topic
                                : PowerDeviceConstants.Topics.CURRENT_COMMAND_TOPIC;
                    })
                    .orElse(PowerDeviceConstants.Topics.CURRENT_COMMAND_TOPIC);
        } catch (Exception ex) {
            return PowerDeviceConstants.Topics.CURRENT_COMMAND_TOPIC;
        }
    }
    
    /**
     * 等待指定路的响应
     */
    public Boolean waitForChannelResponse(String merchantId, int channel, long timeoutMs) {
        String responseKey = PowerDeviceConstants.RedisKeys.POWER_RESPONSE_PREFIX + merchantId + ":" + channel;
        long startTime = System.currentTimeMillis();
        
        while (System.currentTimeMillis() - startTime < timeoutMs) {
            Object response = redisTemplate.opsForValue().get(responseKey);
            if (response != null) {
                redisTemplate.delete(responseKey); // 清除已处理的响应
                return (Boolean) response;
            }
            
            try {
                Thread.sleep(100); // 100ms轮询一次
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            }
        }
        
        log.warn("[电力查询] 商家:{}, {}路响应超时 ({}ms)", merchantId, channel, timeoutMs);
        return null;
    }
    
    /**
     * 解析电力状态响应（Modbus RTU格式）
     */
    private Boolean parsePowerStatus(String hexResponse) {
        if (hexResponse == null || hexResponse.trim().isEmpty()) {
            return null;
        }
        
        try {
            String cleanHex = hexResponse.replace(" ", "").toUpperCase();
            log.info("[响应解析] 原始数据: {}", cleanHex);
            
            // Modbus RTU格式：01 04 02 0000 B930
            // 01 - 设备地址
            // 04 - 功能码
            // 02 - 数据长度
            // 0000 - 实际数据（2字节）
            // B930 - CRC校验
            
            if (cleanHex.length() >= 10) {
                // 提取数据部分（跳过地址、功能码、长度，取数据部分）
                String dataHex = cleanHex.substring(6, 10); // 取0000部分
                int dataValue = Integer.parseInt(dataHex, 16);
                
                // 根据实际设备协议判断：
                // 0000 = 断电，非0000 = 有电
                boolean powerOn = (dataValue != 0);
                
                log.info("[响应解析] 数据解析成功 - 原始:{}, 数据部分:{}, 数值:{}, 状态:{}", 
                        cleanHex, dataHex, dataValue, powerOn ? "有电" : "断电");
                
                return powerOn;
            }
            
            // 兼容旧格式
            String expectedPowerOn = PowerDeviceConstants.POWER_ON_RESPONSE.replace(" ", "").toUpperCase();
            String expectedPowerOff = PowerDeviceConstants.POWER_OFF_RESPONSE.replace(" ", "").toUpperCase();
            
            if (expectedPowerOn.equals(cleanHex)) {
                return true;
            } else if (expectedPowerOff.equals(cleanHex)) {
                return false;
            }
            
            log.warn("[响应解析] 未知响应格式: {} (长度:{})", cleanHex, cleanHex.length());
            return null;
            
        } catch (Exception e) {
            log.error("[响应解析] 解析失败: {}", hexResponse, e);
            return null;
        }
    }
    
    /**
     * 确定响应对应的路数（改进版：按时间顺序匹配最早的查询）
     */
    private Integer determineResponseChannel(String merchantId) {
        Integer matchedChannel = null;
        long earliestTimestamp = Long.MAX_VALUE;
        
        // 查找所有待响应的查询，选择最早的一个
        for (int channel = 1; channel <= PowerDeviceConstants.MAX_CHANNELS; channel++) {
            String queryKey = PowerDeviceConstants.RedisKeys.POWER_QUERY_PREFIX + merchantId + ":" + channel;
            try {
                Object queryData = redisTemplate.opsForValue().get(queryKey);
                if (queryData != null) {
                    long timestamp;
                    if (queryData instanceof Map) {
                        @SuppressWarnings("unchecked")
                        Map<String, Object> queryInfo = (Map<String, Object>) queryData;
                        timestamp = ((Number) queryInfo.get("timestamp")).longValue();
                    } else {
                        timestamp = ((Number) queryData).longValue();
                    }
                    
                    if (timestamp < earliestTimestamp) {
                        earliestTimestamp = timestamp;
                        matchedChannel = channel;
                    }
                    
                    log.debug("[响应匹配] 找到查询记录 - 商家:{}, {}路, 时间戳:{}", 
                            merchantId, channel, timestamp);
                }
            } catch (Exception e) {
                log.warn("[响应匹配] 读取查询记录失败 - 商家:{}, {}路", merchantId, channel, e);
            }
        }
        
        // 清除匹配的查询记录
        if (matchedChannel != null) {
            String matchedKey = PowerDeviceConstants.RedisKeys.POWER_QUERY_PREFIX + merchantId + ":" + matchedChannel;
            redisTemplate.delete(matchedKey);
            log.info("[响应匹配] 成功匹配 - 商家:{}, {}路", merchantId, matchedChannel);
        } else {
            log.warn("[响应匹配] 未找到对应查询记录 - 商家:{}", merchantId);
            
            // 调试：打印所有查询记录
            for (int channel = 1; channel <= PowerDeviceConstants.MAX_CHANNELS; channel++) {
                String queryKey = PowerDeviceConstants.RedisKeys.POWER_QUERY_PREFIX + merchantId + ":" + channel;
                boolean exists = Boolean.TRUE.equals(redisTemplate.hasKey(queryKey));
                log.debug("[调试] 查询记录状态 - Key:{}, 存在:{}", queryKey, exists);
            }
        }
        
        return matchedChannel;
    }
    
    /**
     * 更新单路电源状态到整体状态
     */
    private void updateSingleChannelStatus(String merchantId, Integer channel, Boolean powerStatus) {
        try {
            String statusKey = PowerDeviceConstants.RedisKeys.MERCHANT_STATUS_PREFIX + merchantId;
            
            // 获取现有状态
            Map<Object, Object> existingStatus = redisTemplate.opsForHash().entries(statusKey);
            Map<String, Boolean> channels = new java.util.HashMap<>();
            
            // 如果已有状态，先加载现有的通道状态
            if (!existingStatus.isEmpty() && existingStatus.containsKey("channels")) {
                @SuppressWarnings("unchecked")
                Map<String, Boolean> existingChannels = (Map<String, Boolean>) existingStatus.get("channels");
                channels.putAll(existingChannels);
            }
            
            // 更新当前通道状态
            channels.put(String.valueOf(channel), powerStatus);
            
            // 计算整体断电状态
            boolean allPowerOff = channels.values().stream().noneMatch(Boolean::booleanValue);
            
            // 更新Redis
            Map<String, Object> status = Map.of(
                "allPowerOff", allPowerOff,
                "channels", channels,
                "updateTime", LocalDateTime.now().toString(),
                "channelCount", channels.size()
            );
            
            redisTemplate.opsForHash().putAll(statusKey, status);
            redisTemplate.expire(statusKey, Duration.ofHours(24));
            
            log.info("[电力状态] 单路更新 - 商家:{}, {}路:{}, 整体断电:{}", 
                    merchantId, channel, powerStatus ? "有电" : "断电", allPowerOff);
            log.info("[电力状态] Redis存储详情 - Key:{}, 通道数据:{}", statusKey, channels);
                    
        } catch (Exception e) {
            log.error("[电力状态] 单路状态更新失败 - 商家:{}, {}路", merchantId, channel, e);
        }
    }
    
    /**
     * 更新商家整体电源状态
     */
    private void updateMerchantPowerStatus(String merchantId, Map<Integer, Boolean> channelStatus) {
        // 计算整体断电状态：所有路都断电才算完全断电
        boolean allPowerOff = channelStatus.values().stream().noneMatch(Boolean::booleanValue);
        
        // 将Integer key转换为String key，方便前端使用
        Map<String, Boolean> channelsWithStringKey = new java.util.HashMap<>();
        for (Map.Entry<Integer, Boolean> entry : channelStatus.entrySet()) {
            channelsWithStringKey.put(String.valueOf(entry.getKey()), entry.getValue());
        }
        
        String statusKey = PowerDeviceConstants.RedisKeys.MERCHANT_STATUS_PREFIX + merchantId;
        java.util.HashMap<String, Object> status = new java.util.HashMap<>();
        status.put("allPowerOff", allPowerOff);
        status.put("channels", channelsWithStringKey);
        status.put("updateTime", LocalDateTime.now().toString());
        status.put("channelCount", channelStatus.size());
        
        // 存储到Redis Hash
        redisTemplate.opsForHash().putAll(statusKey, status);
        
        // 设置过期时间（24小时）
        redisTemplate.expire(statusKey, Duration.ofHours(24));
        
        log.info("[电力状态] 商家:{}, 整体断电状态:{}, 各路详情:{}", 
                merchantId, allPowerOff, channelStatus);
    }
}
